package com.motu.monstercity.module.common.verticle;


import com.motu.monstercity.module.common.utility.CmdConstant;
import com.motu.monstercity.module.common.utility.Constant;
import com.motu.monstercity.module.common.utility.ServerVersion;
import com.motu.monstercity.module.common.utility.EventBusConstant;
import com.motu.vertx.module.utility.base.ServerConfig;
import com.motu.vertx.module.utility.base.ServerOpenBase;
import com.motu.vertx.module.utility.base.ServerTypeEnum;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.mysql.MysqlClient;
import com.motu.vertx.module.utility.mysql.MysqlTool;
import com.motu.vertx.module.utility.threadpool.DBLogManager;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

public class GmVerticle extends AbstractVerticle {
    public final static Logger logger = LoggerFactory.getLogger(GmVerticle.class);

    @Override
    public void start(Promise<Void> future) throws Exception {
        String address = EventBusConstant.getAddress(EventBusConstant.GAME_GM);
        MessageConsumer<JsonObject> consumer = MainService.getVertx().eventBus().consumer(address);
        consumer.handler(message -> {
            JsonObject obj = message.body();
            logger.info("###GmVerticle address:" + address + " receive:" + obj.toString());
            String cmd = obj.getString("cmd");
            JsonObject data = obj.getJsonObject("data");
            int serverType = ServerConfig.getServerType();
            if (data.containsKey("servertype")) {
                JsonArray serverTypes = data.getJsonArray("servertype");
                if (!serverTypes.contains(serverType)) {
                    return;
                }
            }
            switch (cmd) {
                case CmdConstant.GM_CMD_RELOAD:
                    handleRoload(data);
                    break;
                case CmdConstant.GM_CMD_RELOAD_WITH_PARAMS:
                    handleReloadWithParams(data);// 重载带参数的方法
                    break;
                case CmdConstant.GM_CMD_CHECK:
                    String sql = "insert into processchecklog(addtime, servertype, ip, version, type) values (unix_timestamp(now()), ?,?,?,?);";
                    JsonArray params = new JsonArray();
                    params.add((serverType == ServerTypeEnum.GAME.value && ServerConfig.isGameInit()) ? ServerTypeEnum.INIT.value : serverType);
                    params.add(Tool.getHostIp());
                    params.add(ServerVersion.VERSION);// 版本号
                    params.add(data.getInteger("type"));
                    MysqlTool.updateToDb(MysqlClient.getServerPool(), sql, params, h -> {
                        if (h.failed()) {
                            logger.error("CheckVerticle receive insert fail!" + h.cause().getMessage());
                        }
                    });
                    break;
                case CmdConstant.GM_CMD_SERVER_OPEN:
                    if (serverType == ServerTypeEnum.WEB.value) {// web进程才执行预约开服
                        handleServerOpen(data);
                    }
                    break;
                default:
                    break;
            }
        });

        consumer.completionHandler(res2 -> {
            if (res2.succeeded()) {
                future.complete();
                logger.info("The GmVerticle handler registration has reached all nodes ebName:" + address);
            } else {
                future.fail(res2.cause());
                logger.error("GmVerticle Registration failed! " + res2.cause().toString());
            }
        });

    }

    // 预约开服
    public void handleServerOpen(JsonObject jsonObject) {
        try {
            int num = jsonObject.getInteger("num");// 开服数量
            ServerOpenBase.serverOpenInterFace.doOpenServer(num, ServerOpenBase.LOG_OPEN_TYPE_2, "");
        } catch (Exception e) {
            logger.error(Tool.getException(e));
        }
    }

    public void handleRoload(JsonObject data) {
        String methodStr = data.getString("method");
        String path = data.getString("path");
        try {
            logger.info("handleRoload method = " + path + methodStr + "........................................");
            String[] param = methodStr.split("\\.");
            String strClass = param[0];// 类
            String strMethod = param[1];// 静态方法
            String packetPath = path;
            Class<?> threadClazz = Class.forName(packetPath + strClass);
            Method method = threadClazz.getMethod(strMethod, null);
            // boolean result = ((Boolean)method.invoke(null, null)).booleanValue();
            method.invoke(null, null);
        } catch (NoSuchMethodException ne) {
            logger.error(Tool.getException(ne));
            DBLogManager.addServerCrashLog(0, "###handler reload fail!!! method:" + path + methodStr);
        } catch (Exception e) {
            logger.error(Tool.getException(e));
            DBLogManager.addServerCrashLog(0, "###handler reload fail!!! method:" + path + methodStr);
        }
    }

    public void handleReloadWithParams(JsonObject data) {
        try {
            logger.info("handleReloadWithParams method = " + data + "........................................");
            String packetPath = data.getString("path");
            String methodStr = data.getString("method");
            String[] param = methodStr.split("\\.");
            String strClass = param[0];// 类
            String strMethod = param[1];// 静态方法

            JsonArray params = data.getJsonArray("params");

            Tool.methodInvokeWithParams(packetPath, strClass, strMethod, params);
        } catch (Exception e) {
            logger.error(Tool.getException(e));
        }
    }

}
